#!/bin/bash
# Author: Narunas Krasauskas
# Purpose: Encrypt or mount encrypted usb devices, also unmount function
# Tested On: Debian GNU/Linux 6.0.7 (squeeze) x86_64
# Version: 1a
# Time: 2013/11/21
# Copyright: GPLv3
# Use with caution! Author doesn't take any responsibility for any damage
# caused using these scripts.

####
####  Core Functions
####

##0 Checking privileges sanity
function __privileges() { # echo -n '#0'; echo ' #'$BASHPID
    if which sudo &> /dev/null; then
        _su=$(which sudo)
        $_su cat /dev/null &> /dev/null
    elif [ $(id -ur) -eq 0 ]; then 
        _su=''
    else
        echo "Please run as \`root' user!"
        exit 1
    fi
    export _su
} ## end of __privileges()

##1 Core variables
function __vars() { # echo -n '#1'; echo ' #'$BASHPID
    _path="$(cd "$(dirname "$0")" && pwd)"
    _ext=0
} ## end of __vars()

##2 Detect USB storage drive when one is attached
function __grab_usb() { # echo -n '#2'; echo ' #'$BASHPID
    echo -e \\n'Waiting for USB drive ...'
    # Determine syslog file
    if [ -f '/var/log/messages' ]; then
        _syslog='/var/log/messages'
    else
        _syslog='/var/log/syslog'
    fi
    # Set wait time index and grab usb device
    _max_wait_time="100"
    _time_hop="0.2"
    while [ "${_i:=0}" -lt "${_max_wait_time}" ]; do
        _usb_dev=$($_su tail -n1 ${_syslog} | grep -who 'sd.')
        case $? in
            0)  # When device is found
                #$_su umount /dev/${_usb_dev} &> /dev/null
                $_su umount /dev/${_usb_dev}* &> /dev/null
                _i=300 && sleep 1
                echo -e \\n'New USB storage device has been found:'\\n
                $_su fdisk -l /dev/${_usb_dev} | grep -A0 'Disk /dev'
                $_su fdisk -l /dev/${_usb_dev} | grep -A10 'Device Boot' | tail -n+2
            ;;
            *)  # If device is not present, retry shortly after
                _i=$(($_i+1)) && sleep ${_time_hop}
                if [ "${_i}" -ge "${_max_wait_time}" ]; then
                    echo -e "Max wait time was exceeded: $(printf '%1.0f' $(echo ${_max_wait_time}*${_time_hop}|bc)) sec..\n"
                    exit 1
                fi
            ;;
        esac
    done; unset _i
} ## end of __grab_usb()

##3
function __part_nfo() { # echo -n '#3'; echo ' #'$BASHPID
    $_su umount /dev/${_usb_dev}* &> /dev/null
    # If device exists, than record it's parameters
    if test -b /dev/${_usb_dev}1; then
        #_usb_uuid=$($_su blkid /dev/${_usb_dev}1 | sed 's/^.*uuid="//gi' | sed 's/".*//g')
        #_usb_fs=$($_su blkid /dev/${_usb_dev}1 | sed 's/^.*type="//gi' | sed 's/".*//g')
        _usb_uuid=$($_su blkid -s UUID -o value /dev/${_usb_dev}1)
        _usb_fs=$($_su blkid -s TYPE -o value /dev/${_usb_dev}1)
        _usb_label="usbC-$(echo ${_usb_uuid: -6})"
        echo -e "\nCreated variables:\nusb_uuid ->  $_usb_uuid \nusb_fs ->  $_usb_fs \nusb_label ->  $_usb_label\n"
        if echo $_usb_fs | grep -iq 'luks'; then
            echo -e \\n"Device has encrypted partition \`/dev/${_usb_dev}1' of type \`${_usb_fs}'"
            echo -n "Would you like to unlock/mount it? (Y/n): "
        else
            echo -e \\n"Device has no encrypted partitions!"
            echo -n "Would you like to initialize one? (Y/n): "
        fi
    else
        echo -e \\n"Device has no partitions at all!"
        echo -n "Would you like to initialize & encrypt one? (Y/n): "
    fi
    read _ans
} # end of __part_nfo()

##4 
function __part_init() { # echo -n '#4'; echo ' #'$BASHPID
    $_su umount /dev/${_usb_dev}* &> /dev/null
    #dd if=/dev/zero of=/dev/${_usb_dev} bs=512B count=1 &> /dev/null
    _format='o\nn\np\n1\n4\n\na\n1\nw'
    $_su echo -e ${_format} | $_su fdisk /dev/${_usb_dev} &> /dev/null; _ext=$(($_ext+$?)) && sleep 1
    $_su sync &> /dev/null; _ext=$(($_ext+$?))
    test $_ext -eq 0 && echo -e \\n'Initial partitioning completed successfully:' &&\
    $_su fdisk -l /dev/${_usb_dev} && sleep 2
} # end of __part_init()

##5
function __luks_key() { # echo -n '#5'; echo ' #'$BASHPID
    while [ "${_i:=0}" -eq 0 ]; do
        echo -ne \\n'Please specify luks_key path: '
        read _ans
        #(test -f "$_path/$_ans" -a $(stat -c%s "$_path/$_ans") -le 2097152) && { _i=1; _luks_key="$_path/$_ans"; }
        if (test -f "$_ans" -a $(stat -c%s "$_ans") -le 2097152); then
            { _i=1; _luks_key="$_ans"; }
        elif (test -f "$_path/$_ans" -a $(stat -c%s "$_path/$_ans") -le 2097152); then
            { _i=1; _luks_key="$_path/$_ans"; }
        else
            echo "No valid key at specified path."
        fi
    done; unset _i
    echo "Chosen luks_key -->  $_luks_key"
} # end of __luks_key()

##6
function __luks_init() { # echo -n '#6'; echo ' #'$BASHPID
    $_su umount /dev/${_usb_dev}* &> /dev/null
    $_su cryptsetup -q luksFormat /dev/${_usb_dev}1 --key-file "${_luks_key}" && sleep 1
} # end of __luks_init()

##7
function __make_fs() { # echo -n '#7'; echo ' #'$BASHPID
    $_su umount /dev/${_usb_dev}* &> /dev/null
    $_su mke2fs -t ext4 -L ${_usb_label} /dev/mapper/${_usb_label}
} # end of __make_fs()

##8
function __luks_open() { # echo -n '#8'; echo ' #'$BASHPID
    $_su umount /dev/${_usb_dev}* &> /dev/null
    $_su cryptsetup -q luksOpen /dev/${_usb_dev}1 ${_usb_label} --key-file "${_luks_key}" && sleep 1
} # end of __luks_open()

##9
function __luks_mount() { # echo -n '#9'; echo ' #'$BASHPID
    test -d /tmp/${_usb_label} || mkdir -p /tmp/${_usb_label}
    $_su mount -t ext4 /dev/mapper/${_usb_label} /tmp/${_usb_label} &&\
    echo -e \\n"Please find your filesystem at: /tmp/${_usb_label}"
} # end of __luks_mount()

##10
function __usb_umount() { # echo -n '#10'; echo ' #'$BASHPID
    _df=$($_su df -P | grep -Ei '/dev/mapper/usbc-\w+')
    if test $? -eq 0; then 
        echo -e \\n"Found mounted leftovers from the previous sessions:"
        echo $_df | grep -Eoi '/tmp/usbc-\w+'
        echo -ne \\n"Would you like to free up mount points and remove devices? (Y/n): "
        read _ans
        case $_ans in
            Y) 
                $_su umount -vf $(echo $_df | grep -Eoi '/dev/mapper/usbc-\w+') && sleep 1
                echo -n "Cryptsetup: "; $_su cryptsetup remove -v $(echo $_df | grep -Eoi '/dev/mapper/usbc-\w+') 
            ;;
        esac
    fi
} # end of __usb_umount()

####
####  Core Logic
####

__privileges;
__vars;
__usb_umount;
__grab_usb;
__part_nfo;

if test "$_ans" == 'Y' && echo $_usb_fs | grep -iq 'luks'; then
# echo -n '##1'; echo ' #'$BASHPID
    __luks_key || exit 11
    __luks_open || exit 12
    __luks_mount || exit 13
elif test "$_ans" == 'Y' && ! echo $_usb_fs | grep -iq 'luks'; then
# echo -n '##2'; echo ' #'$BASHPID
    __part_init && sleep 1 || exit 21
    __luks_key && sleep 1 || exit 22
    __luks_init && sleep 1 || exit 23
    __luks_open && sleep 1 || exit 24
    __make_fs && sleep 1 || exit 25
    __luks_mount && sleep 1 || exit 26
else
    exit 1
fi
